package org.apache.dolphinscheduler.api.service.impl;

import org.apache.dolphinscheduler.api.enums.ExecuteType;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.ExecutorService;
import org.apache.dolphinscheduler.api.service.ProductOrderService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.enums.WorkflowExecutionStatus;
import org.apache.dolphinscheduler.common.utils.DateUtils;
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition;
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
import org.apache.dolphinscheduler.dao.entity.ProductOrder;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper;
import org.apache.dolphinscheduler.dao.mapper.ProcessInstanceMapper;
import org.apache.dolphinscheduler.dao.mapper.ProductOrderItemMapper;
import org.apache.dolphinscheduler.dao.mapper.ProductOrderMapper;
import org.apache.dolphinscheduler.dao.vo.CountVo;
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;

import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author denggh
 * @since 2023-06-15
 */
@Service
public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, ProductOrder>
        implements
            ProductOrderService {

    private static final Logger logger = LoggerFactory.getLogger(ProductOrderServiceImpl.class);

    @Autowired
    private ProductOrderMapper productOrderMapper;
    @Autowired
    private ProductOrderItemMapper productOrderItemMapper;
    @Autowired
    private ExecutorService executorService;
    @Autowired
    private ProcessInstanceMapper processInstanceMapper;
    @Autowired
    private ProcessDefinitionMapper processDefinitionMapper;

    @Override
    public Result queryProductOrderListPaging(User loginUser, Integer pageSize, Integer pageNo, Integer orderType,
                                              Integer payModel, Integer taskStatus, Integer payStatus) {
        Result result = new Result();
        Page<ProductOrder> page = new Page<>(pageNo, pageSize);
        Integer userId = null;
        if (!isAdmin(loginUser)) {
            userId = loginUser.getId();
        }
        IPage<ProductOrder> list =
                productOrderMapper.queryProductOrderPage(page, userId, orderType, payModel, taskStatus, payStatus);
        PageInfo<ProductOrder> pageInfo = new PageInfo<>(pageNo, pageSize);
        pageInfo.setTotal((int) list.getTotal());
        pageInfo.setTotalList(list.getRecords());
        result.setData(pageInfo);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Result getProductOrder(Integer id) {
        Result result = new Result();
        JSONObject data = new JSONObject();
        ProductOrder productOrder = productOrderMapper.findProductOrder(id);
        if (productOrder == null) {
            return Result.error(Status.PRODUCT_ORDER_NOT_EXIST);
        }
        data.put("detail", productOrder);
        data.put("items", productOrderItemMapper.queryProductOrderItemList(id));
        result.setData(data);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Result cancelProductOrder(User loginUser, Integer id) {
        ProductOrder productOrder = getById(id);
        if (productOrder == null) {
            return Result.error(Status.PRODUCT_ORDER_NOT_EXIST);
        }
        ProcessInstance processInstance = processInstanceMapper.selectById(productOrder.getProcessInstanceId());
//        logger.info("processInstance: "+JSONObject.toJSONString(processInstance));
        if (processInstance != null &&
                (processInstance.getState().equals(WorkflowExecutionStatus.SUBMITTED_SUCCESS)
                        || processInstance.getState().equals(WorkflowExecutionStatus.RUNNING_EXECUTION))) {
            ProcessDefinition processDefinition =
                    processDefinitionMapper.queryByCode(processInstance.getProcessDefinitionCode());
            if (processDefinition != null) {
                logger.info("stop process");
                executorService.execute(loginUser, processDefinition.getProjectCode(),
                        productOrder.getProcessInstanceId(), ExecuteType.STOP);
            }
        }
        BigDecimal zero = new BigDecimal(0);
        Date now = DateUtils.getCurrentDate();
        productOrder.setAmount(zero);
        productOrder.setDiscountAmount(zero);
        productOrder.setRealAmount(zero);
        productOrder.setTaskStatus(2);
        productOrder.setPayStatus(2);
//        productOrder.setPayTime(now);
        productOrder.setEndTime(now);
        updateById(productOrder);

        productOrderItemMapper.updateStateByProductOrderId(productOrder.getId(), productOrder.getTaskStatus());
        Result result = new Result();
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Result countProductOrder(User loginUser, int type, Date startDate, Date endDate) {
        Result result = new Result();
        Integer userId = null;
        if (!isAdmin(loginUser)) {
            userId = loginUser.getId();
        }
        if (type == 0) {
            List<CountVo> resultList = new ArrayList<>();
            CountVo countVo0 = new CountVo();
            countVo0.setTitle("任务资源金额");
            countVo0.setValue(new BigDecimal(0));

            CountVo countVo1 = new CountVo();
            countVo1.setTitle("模型资源金额");
            countVo1.setValue(new BigDecimal(0));
            List<CountVo> list = productOrderMapper.sumAmountByOrderType(userId, startDate, endDate);
            for (CountVo countVo : list) {
                if (countVo == null || StringUtils.isBlank(countVo.getTitle())) {
                    continue;
                }
                if (countVo.getTitle().equals("0")) {
                    countVo0.setValue(countVo.getValue());
                } else if (countVo.getTitle().equals("1")) {
                    countVo1.setValue(countVo.getValue());
                }
            }
            resultList.add(countVo0);
            resultList.add(countVo1);
            result.setData(resultList);
            result.setCode(Status.SUCCESS.getCode());
        } else {
            List<CountVo> list = productOrderMapper.countTaskByScene(userId, startDate, endDate);
            List<CountVo> resultList = new ArrayList<>();
            CountVo countVo0 = new CountVo();
            countVo0.setTitle("大数据计算场景任务数量");
            countVo0.setValue(new BigDecimal(0));

            CountVo countVo1 = new CountVo();
            countVo1.setTitle("科学计算场景任务数量");
            countVo1.setValue(new BigDecimal(0));

            CountVo countVo2 = new CountVo();
            countVo2.setTitle("智能计算场景任务数量");
            countVo2.setValue(new BigDecimal(0));
            for (CountVo countVo : list) {
                if (countVo == null || StringUtils.isBlank(countVo.getTitle())) {
                    continue;
                }
                if (countVo.getTitle().equals("0")) {
                    countVo0.setValue(countVo.getValue());
                } else if (countVo.getTitle().equals("1")) {
                    countVo1.setValue(countVo.getValue());
                } else if (countVo.getTitle().equals("2")) {
                    countVo2.setValue(countVo.getValue());
                }
            }
            resultList.add(countVo0);
            resultList.add(countVo1);
            resultList.add(countVo2);
            result.setData(resultList);
            result.setCode(Status.SUCCESS.getCode());
        }
        return result;
    }

    @Override
    public Result countProductOrderTop3(User loginUser) {
        Integer userId = null;
        if (!isAdmin(loginUser)) {
            userId = loginUser.getId();
        }
        List<CountVo> list = productOrderMapper.countProductOrderTop3(userId,DateUtils.getCurrentDate());
        return Result.success(list);
    }

    public void putMsg(Result result, Status status, Object... statusParams) {
        result.setCode(status.getCode());
        if (statusParams != null && statusParams.length > 0) {
            result.setMsg(MessageFormat.format(status.getMsg(), statusParams));
        } else {
            result.setMsg(status.getMsg());
        }
    }
    public boolean isAdmin(User user) {
        return (user.getRoleId() != null && user.getRoleId().intValue() == 1);
    }
}
